#!/usr/bin/env python

##  flamingo - 2D Game Engine
##  Copyright (C) 2009 Bradley Zeis
##
##  This program is free software: you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation, either version 3 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##  Bradley Zeis
##  flamingoengine@gmail.com

"""Flamingo audio mixer backend for the Pygame mixer.

pygamemixer requires the pygame.mixer module, so it may not work on all
systems. It also has many limitations compared to the default mixer:

    - You can't pan
    - You can't use effects
    - You can't position the sounds in the 2d world
    - You can only stream one file at a time

Supported Formats:
    - Ogg Vorbix (.ogg)
    - Wave (.wav)
"""
import numpy
import pygame

from ... import core
import abstractmixer

try:
    pygame.mixer.init()
except:
    raise ImportError, "pygame.mixer not available."

##-------- Constants
SAMPLERATE = 0
CHANNELS = 0
CHUNKSIZE = 0

THREADED = False

##-------- Functions
def init(samplerate=44100, channels=2, chunksize=1024):
    """Initialize the mixer.

    samplerate      - (int) The number of samples per second.
    channels        - (int) The number of stereo channels to use
    chunksize       - (int) The number of samples processed at a time.

    Returns: None
    """
    
    pygame.mixer.init()
    
    global SAMPLERATE, CHANNELS, CHUNKSIZE
    SAMPLERATE = samplerate
    CHANNELS = channels
    CHUNKSIZE = chunksize

    pygame.mixer.quit()
    pygame.mixer.init(samplerate, 16, channels, chunksize)
    Channel()

def start():
    """Start a new mixing thread."""
    pass

def quit():
    pygame.mixer.quit()

def ms_to_samp(ms):
    return int(ms * (SAMPLERATE / 1000.0))

def samp_to_ms(samp):
    return int(samp / (SAMPLERATE / 1000.0))

##-------- Sounds
class Sound(abstractmixer.Sound):
    """A sound loaded completely into memory."""
    def __init__(self, filename):
        self.data = pygame.sndarray.array(pygame.mixer.Sound(filename))
        self.sound = None

    def play(self, channel=0, volume=1.0, loops=0, *args, **kwargs):
        d = self.data.copy()
        d *= volume
        Mixer.channels[channel].add_src(d, self, loops)
        return self

    def resample(self, samplerate):
        pass

    def pause(self):
        if self.sound:
            self.sound.pause()

    def unpause(self):
        if self.sound:
            self.sound.unpause()

    def stop(self):
        if self.sound:
            self.sound.stop()

    length = property(lambda: len(self.data))

class StreamingSound(abstractmixer.StreamingSound):
    """A sound streamed directly from disk."""
    def __init__(self, filename):
        self.data = pygame.mixer.music.load(filename)

    def play(self, channel=0, volume=1.0, loops=0, *args, **kwargs):
        Mixer.channels[channel].volume = volume
        Mixer.channels[channel].add_src("stream", self, loops)
        return self

    def pause(self):
        pygame.mixer.music.pause()

    def unpause(self):
        pygame.mixer.music.unpause()

    def stop(self):
        pygame.mixer.music.stop()

##-------- Mixer
class Channel(abstractmixer.Channel):
    """A "mixer channel"/Group."""
    def __init__(self, volume=1.0):
        Mixer.channels.append(self)
        self.srcs = []
        self.volume = volume

    def add_src(self, src, original, *args):
        self.srcs.append([src, original, args])

    def add_effect(self, effect):
        pass

class Mixer(abstractmixer.Mixer):
    """A collection of Channels."""
    channels = []

    @classmethod
    def tick(self, dt):
        out = numpy.zeros((CHUNKSIZE, 2), numpy.float)

        for ch in self.channels:
            for src in ch.srcs:
                if src[0] == "stream":
                    pygame.mixer.music.set_volume(ch.volume)
                    pygame.mixer.music.play(*src[2])
                    continue

                src[0] *= ch.volume

                s = pygame.sndarray.make_sound(src[0])
                src[1].sound = s.play(*src[2])

            ch.srcs = []
